package com.sanyou.utils;

import java.lang.management.ManagementFactory;
import java.net.NetworkInterface;
import java.net.SocketException;
import java.util.Enumeration;
import java.util.Random;

public class SnowFlake {
    //机器码位数
    private static long machineBtis = 5L;
    //数据中心（进程号）位数
    private static long dataCenterBits = 5L;
    //时间戳位数
    private static long timeStampBits = 41L;
    //随机序列位数
    private static long randomSequenceBits = 12L;

    //时间戳左移位数
    private static long timeStampShift = dataCenterBits+randomSequenceBits+machineBtis;
    //机器码id左移位数
    private static long machineShift = dataCenterBits+randomSequenceBits;
    //数据中心左移位数
    private static long dataCenterShift = randomSequenceBits;

    //机器码id
    private static long machineId = 1L;
    //数据中心（进程号）id
    private static long dataCenterId = 1L;
    //时间戳
    private static long timeStampId = -1L;
    //随机序列位数
    private static long randomSequence = 1L;
    //上一次时间戳
    private static long lastTimeStamp = -1L;

    private static SnowFlake snowFlake = new SnowFlake();

    private static Long id;


    public static Long getNextId() throws Exception {
        id = (snowFlake.getTimeStampId()<<timeStampShift)|(snowFlake.getMachineId()<<machineShift)|(snowFlake.getDataCenterId()<<dataCenterShift)|(snowFlake.getRandomSequenceId());
        return id;
    }

    private long getRandomSequenceId(){
        Random random = new Random();
        long randomMask = -1L ^ (-1L << randomSequenceBits);
        return random.nextLong()&randomMask;
    }

    private long getDataCenterId(){
        String processId = ManagementFactory.getRuntimeMXBean().getName().split("@")[0];
        long processMask = -1L ^ (-1L << dataCenterBits);
        return Long.valueOf(processId)&processMask;
    }

    private long getMachineId() throws SocketException {
        StringBuilder stringBuilder = new StringBuilder();
        Enumeration<NetworkInterface> networkInterfaceEnumeration = NetworkInterface.getNetworkInterfaces();
        while(networkInterfaceEnumeration.hasMoreElements()){
            stringBuilder.append(networkInterfaceEnumeration.nextElement().getName());
        }
        long machineMask = -1L^ (-1L << machineBtis);
        return stringBuilder.toString().hashCode()&machineMask;
    }

    public long getTimeStampId() throws Exception {
        long time = System.currentTimeMillis();
        if(time<lastTimeStamp){
            throw new Exception("clock moved backward");
        }
        lastTimeStamp = time;
        long timeStampMask = -1L^ (-1L << timeStampBits);
        return time&timeStampMask;
    }
}
